/*
 * DevicesIIC.c
 *
 *      Author: Honrun
 */

#include "gd32w51x.h"
#include "stdio.h"
#include "version.h"
#include "DevicesDelay.h"
#include "DevicesIIC.h"




void vIIC0Init(void)
{
    /* enable GPIOB clock */
    rcu_periph_clock_enable(RCU_GPIOB);
    /* enable GPIOC clock */
    rcu_periph_clock_enable(RCU_GPIOA);
    /* enable I2C1 clock */
    rcu_periph_clock_enable(RCU_I2C0);

    /* connect I2C_SDA */
    gpio_af_set(GPIOB, GPIO_AF_4, GPIO_PIN_7);
    /* connect I2C_SCL */
    gpio_af_set(GPIOA, GPIO_AF_4, GPIO_PIN_15);

    /* configure GPIO pins of I2C1 */
    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_7);
    gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_25MHZ, GPIO_PIN_7);
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_15);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_OD, GPIO_OSPEED_25MHZ, GPIO_PIN_15);

    vIIC0DMAInit();

    /* configure I2C timing */
    i2c_timing_config(I2C0, 0, 0x4, 0);
    i2c_master_clock_config(I2C0, 45, 45);
    /* enable I2C */
    i2c_enable(I2C0);
}


/*!
    \brief      reset i2c bus
    \param[in]  none
    \param[out] none
    \retval     none
*/
void vIIC0DeInit(void)
{
    int8_t i = 0;

    /* configure SDA/SCL for GPIO */
    gpio_bit_set(GPIOB, GPIO_PIN_7);
    gpio_bit_set(GPIOA, GPIO_PIN_15);

    /* reset PB15 and PA8 */
    gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_7);
    gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, GPIO_PIN_7);
    gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_15);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, GPIO_PIN_15);

    vDelayUs(100);

    /* 发送10个时钟脉冲，以解除死锁 */
    for(i = 0; i < 9; ++i)
    {
        gpio_bit_reset(GPIOA, GPIO_PIN_15);
        vDelayUs(5);
        gpio_bit_set(GPIOA, GPIO_PIN_15);
        vDelayUs(5);
    }

    /* connect I2C_SDA */
    gpio_af_set(GPIOB, GPIO_AF_4, GPIO_PIN_7);
    /* connect I2C_SCL */
    gpio_af_set(GPIOA, GPIO_AF_4, GPIO_PIN_15);

    /* connect PB15 to I2C1_SCL */
    /* connect PA8 to I2C1_SDA */
    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_7);
    gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_25MHZ, GPIO_PIN_7);
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_15);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_OD, GPIO_OSPEED_25MHZ, GPIO_PIN_15);
}

void vIIC0DMAInit(void)
{
    dma_single_data_parameter_struct dma_init_struct = {0};
    uint8_t ucDMASendByte, ucDMAReadByte = 0;

    /* enable DMA clock */
    rcu_periph_clock_enable(RCU_DMA0);

    /* initialize DMA0 channel7 for I2C_TX */
    dma_deinit(DMA0, DMA_CH7);
    dma_single_data_para_struct_init(&dma_init_struct);
    dma_init_struct.direction = DMA_MEMORY_TO_PERIPH;
    dma_init_struct.memory0_addr = (uint32_t)&ucDMASendByte;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.periph_memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct.circular_mode = DMA_CIRCULAR_MODE_DISABLE;
    dma_init_struct.number = 0;
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.periph_addr = (uint32_t)&I2C_TDATA(I2C0);
    dma_init_struct.priority = DMA_PRIORITY_HIGH;
    dma_single_data_mode_init(DMA0, DMA_CH7, &dma_init_struct);

    /* DMA channel peripheral select */
    dma_channel_subperipheral_select(DMA0, DMA_CH7, DMA_SUBPERI1);

    /* enable I2CX transmit DMA */
    i2c_dma_enable(I2C0, I2C_DMA_TRANSMIT);
    /* enable DMA channel7 for I2CX transmit */
    dma_channel_disable(DMA0, DMA_CH7);


    /* initialize DMA0 channel7 for I2C_RX */
    dma_deinit(DMA0, DMA_CH0);
    dma_init_struct.direction = DMA_PERIPH_TO_MEMORY;
    dma_init_struct.memory0_addr = (uint32_t)&ucDMAReadByte;
    dma_init_struct.periph_addr = (uint32_t)&I2C_RDATA(I2C0);
    dma_single_data_mode_init(DMA0, DMA_CH0, &dma_init_struct);

    /* DMA channel peripheral select */
    dma_channel_subperipheral_select(DMA0, DMA_CH0, DMA_SUBPERI1);

    /* enable I2CX receive DMA */
    i2c_dma_enable(I2C0, I2C_DMA_RECEIVE);
    /* enable DMA channel7 for I2CX receive */
    dma_channel_disable(DMA0, DMA_CH0);
}

void vIIC1Init(void)
{
    /* enable GPIOA clock */
    rcu_periph_clock_enable(RCU_GPIOA);
    /* enable GPIOB clock */
    rcu_periph_clock_enable(RCU_GPIOB);
    /* enable I2C1 clock */
    rcu_periph_clock_enable(RCU_I2C1);

    /* connect PA8 to I2C1_SDA */
    gpio_af_set(GPIOA, GPIO_AF_6, GPIO_PIN_8);
    /* connect PB15 to I2C1_SCL */
    gpio_af_set(GPIOB, GPIO_AF_6, GPIO_PIN_15);
    /* configure GPIO pins of I2C1 */
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_8);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_OD, GPIO_OSPEED_25MHZ, GPIO_PIN_8);
    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_15);
    gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_25MHZ, GPIO_PIN_15);

    vIIC1DMAInit();

    /* configure I2C timing */
    i2c_timing_config(I2C1, 0, 0x4, 0);
    i2c_master_clock_config(I2C1, 0x1A, 0x4F);

    /* enable I2C1 */
    i2c_enable(I2C1);
}


/*!
    \brief      reset i2c bus
    \param[in]  none
    \param[out] none
    \retval     none
*/
void vIIC1DeInit(void)
{
    int8_t i = 0;

    /* configure SDA/SCL for GPIO */
    gpio_bit_set(GPIOB, GPIO_PIN_15);
    gpio_bit_set(GPIOA, GPIO_PIN_8);

    /* reset PB15 and PA8 */
    gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_15);
    gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, GPIO_PIN_15);
    gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_8);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, GPIO_PIN_8);

    vDelayUs(100);

    /* 发送10个时钟脉冲，以解除死锁 */
    for(i = 0; i < 9; ++i)
    {
        gpio_bit_reset(GPIOB, GPIO_PIN_15);
        vDelayUs(5);
        gpio_bit_set(GPIOB, GPIO_PIN_15);
        vDelayUs(5);
    }

    /* connect PA8 to I2C1_SDA */
    gpio_af_set(GPIOA, GPIO_AF_6, GPIO_PIN_8);
    /* connect PB15 to I2C1_SCL */
    gpio_af_set(GPIOB, GPIO_AF_6, GPIO_PIN_15);

    /* connect PB15 to I2C1_SCL */
    /* connect PA8 to I2C1_SDA */
    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_15);
    gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_25MHZ, GPIO_PIN_15);
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_8);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_OD, GPIO_OSPEED_25MHZ, GPIO_PIN_8);
}

void vIIC1DMAInit(void)
{
    dma_single_data_parameter_struct dma_init_struct = {0};
    uint8_t ucDMASendByte, ucDMAReadByte = 0;

    /* enable DMA clock */
    rcu_periph_clock_enable(RCU_DMA0);

    /* initialize DMA0 channel7 for I2C_TX */
    dma_deinit(DMA0, DMA_CH7);
    dma_single_data_para_struct_init(&dma_init_struct);
    dma_init_struct.direction = DMA_MEMORY_TO_PERIPH;
    dma_init_struct.memory0_addr = (uint32_t)&ucDMASendByte;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.periph_memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct.circular_mode = DMA_CIRCULAR_MODE_DISABLE;
    dma_init_struct.number = 0;
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.periph_addr = (uint32_t)&I2C_TDATA(I2C1);
    dma_init_struct.priority = DMA_PRIORITY_HIGH;
    dma_single_data_mode_init(DMA0, DMA_CH7, &dma_init_struct);

    /* DMA channel peripheral select */
    dma_channel_subperipheral_select(DMA0, DMA_CH7, DMA_SUBPERI7);

    /* enable I2CX transmit DMA */
    i2c_dma_enable(I2C1, I2C_DMA_TRANSMIT);
    /* enable DMA channel7 for I2CX transmit */
    dma_channel_disable(DMA0, DMA_CH7);


    /* initialize DMA0 channel7 for I2C_RX */
    dma_deinit(DMA0, DMA_CH2);
    dma_init_struct.direction = DMA_PERIPH_TO_MEMORY;
    dma_init_struct.memory0_addr = (uint32_t)&ucDMAReadByte;
    dma_init_struct.periph_addr = (uint32_t)&I2C_RDATA(I2C1);
    dma_single_data_mode_init(DMA0, DMA_CH2, &dma_init_struct);

    /* DMA channel peripheral select */
    dma_channel_subperipheral_select(DMA0, DMA_CH2, DMA_SUBPERI7);

    /* enable I2CX receive DMA */
    i2c_dma_enable(I2C1, I2C_DMA_RECEIVE);
    /* enable DMA channel7 for I2CX receive */
    dma_channel_disable(DMA0, DMA_CH2);
}



int8_t cI2CxWriteDatas(uint32_t i2c_periph, uint16_t usIDAddr, uint16_t usRegAddr, uint8_t* pBuffer, int32_t iLength)
{
    void (*vI2CxBusReset)(void) = NULL;
    int32_t timeout = 0, startCnt = 0;

    if(iLength <= 0)
        return -1;

    vI2CxBusReset = (i2c_periph == I2C0) ? vIIC0DeInit : vIIC1DeInit;

    /* i2c master sends start signal only when the bus is idle */
    for(timeout = 0; i2c_flag_get(i2c_periph, I2C_FLAG_I2CBSY) != RESET; ++timeout)
    {
        if(timeout > I2C_BUSY_TIME_OUT)
        {
            vI2CxBusReset();
            printf("cI2C %08X busy.\r\n", i2c_periph);
            return -2;
        }
    }

    /* 重试 N 次 */
    for(startCnt = 0; startCnt < I2C_START_OUT; ++startCnt)
    {
        if(startCnt >= I2C_START_OUT)
        {
            vI2CxBusReset();
            printf("cI2C %08X start out.\r\n", i2c_periph);
            return -3;
        }

        /* configure slave address */
        i2c_master_addressing(i2c_periph, usIDAddr, I2C_MASTER_TRANSMIT);
        /* configure number of bytes to be transferred */
        i2c_transfer_byte_number_config(i2c_periph, iLength + 1);
        /* clear I2C_TDATA register */
        I2C_STAT(i2c_periph) |= I2C_STAT_TBE;
        /* disable I2C automatic end mode in master mode */
        i2c_automatic_end_enable(i2c_periph);

        i2c_start_on_bus(i2c_periph);
        /* wait until the transmit data buffer is empty */
        for(timeout = 0; timeout < I2C_BUSY_TIME_OUT; ++timeout)
        {
            if(i2c_flag_get(i2c_periph, I2C_FLAG_TBE) != RESET)
            {
                break;
            }
        }

        /* send address */
        i2c_data_transmit(i2c_periph, usRegAddr);
        /* wait until the transmit data buffer is empty */
        for(timeout = 0; timeout < I2C_BYTE_TIME_OUT; ++timeout)
        {
            if(i2c_flag_get(i2c_periph, I2C_FLAG_TI) != RESET)
            {
                break;
            }
        }

        if(timeout < I2C_BYTE_TIME_OUT)
            break;
    }

    while((iLength--) > 0)
    {
        /* wait until the transmit data buffer is empty */
        for(timeout = 0; timeout < I2C_BYTE_TIME_OUT; ++timeout)
        {
            if(i2c_flag_get(i2c_periph, I2C_FLAG_TI) != RESET)
            {
                break;
            }
        }

        /* send address */
        i2c_data_transmit(i2c_periph, *pBuffer++);
    }

    /* wait until the stop condition is finished */
    for(timeout = 0; i2c_flag_get(i2c_periph, I2C_FLAG_STPDET) == RESET; ++timeout)
    {
        if(timeout > (I2C_BUSY_TIME_OUT * iLength))
        {
            vI2CxBusReset();
            printf("cI2C %08X stpdet.\r\n", i2c_periph);
            return -5;
        }
    }

    /* clear STPDET flag */
    i2c_flag_clear(i2c_periph, I2C_FLAG_STPDET);

    return 0;
}

int8_t cI2CxReadDatas(uint32_t i2c_periph, uint16_t usIDAddr, uint16_t usRegAddr, uint8_t* pBuffer, int32_t iLength)
{
    void (*vI2CxBusReset)(void) = NULL;
    int32_t timeout = 0, startCnt = 0;

    if(iLength <= 0)
        return -1;

    vI2CxBusReset = (i2c_periph == I2C0) ? vIIC0DeInit : vIIC1DeInit;

    /* i2c master sends start signal only when the bus is idle */
    for(timeout = 0; i2c_flag_get(i2c_periph, I2C_FLAG_I2CBSY) != RESET; ++timeout)
    {
        if(timeout > I2C_BUSY_TIME_OUT)
        {
            vI2CxBusReset();
            printf("cI2C %08X busy.\r\n", i2c_periph);
            return -2;
        }
    }

    /* 重试 N 次 */
    for(startCnt = 0; startCnt < I2C_START_OUT; ++startCnt)
    {
        if(startCnt >= I2C_START_OUT)
        {
            vI2CxBusReset();
            printf("cI2C %08X start timeout.\r\n", i2c_periph);
            return -3;
        }

        /* clear I2C_TDATA register */
        I2C_STAT(i2c_periph) |= I2C_STAT_TBE;
        /* configure slave address */
        i2c_master_addressing(i2c_periph, usIDAddr, I2C_MASTER_TRANSMIT);
        /* configure number of bytes to be transferred */
        i2c_transfer_byte_number_config(i2c_periph, 1);
        /* disable I2C automatic end mode in master mode */
        i2c_automatic_end_disable(i2c_periph);

        i2c_start_on_bus(i2c_periph);
        /* wait until the transmit data buffer is empty */
        for(timeout = 0; timeout < I2C_BUSY_TIME_OUT; ++timeout)
        {
            if(i2c_flag_get(i2c_periph, I2C_FLAG_TBE) != RESET)
            {
                break;
            }
        }

        /* send address */
        i2c_data_transmit(i2c_periph, usRegAddr);
        /* wait until the transmit data buffer is empty */
        for(timeout = 0; timeout < I2C_BYTE_TIME_OUT; ++timeout)
        {
            if(i2c_flag_get(i2c_periph, I2C_FLAG_TC) != RESET)
            {
                break;
            }
        }

        if(timeout < I2C_BYTE_TIME_OUT)
            break;
    }

    /* configure one byte address */
    i2c_master_addressing(i2c_periph, usIDAddr, I2C_MASTER_RECEIVE);
    /* configure number of bytes to be transferred */
    i2c_transfer_byte_number_config(i2c_periph, iLength);
    /* enable I2C automatic end mode in master mode */
    i2c_automatic_end_enable(i2c_periph);

    /* restart */
    i2c_start_on_bus(i2c_periph);
    /* wait until the transmit data buffer is empty */
    for(timeout = 0; timeout < I2C_BUSY_TIME_OUT; ++timeout)
    {
        if(i2c_flag_get(i2c_periph, I2C_FLAG_TBE) != RESET)
        {
            break;
        }
    }

    while((iLength--) > 0)
    {
        /* wait until the RBNE bit is set */
        for(timeout = 0; timeout < I2C_BYTE_TIME_OUT; ++timeout)
        {
            if(i2c_flag_get(i2c_periph, I2C_FLAG_RBNE) != RESET)
            {
                break;
            }
        }

        /* read a data from I2C_RDATA */
        *pBuffer++ = i2c_data_receive(i2c_periph);
    }

    /* wait until the stop condition is finished */
    for(timeout = 0; i2c_flag_get(i2c_periph, I2C_FLAG_STPDET) == RESET; ++timeout)
    {
        if(timeout > (I2C_BUSY_TIME_OUT * iLength))
        {
            vI2CxBusReset();
            printf("cI2C %08X stpdet.\r\n", i2c_periph);
            return -5;
        }
    }

    /* clear STPDET flag */
    i2c_flag_clear(i2c_periph, I2C_FLAG_STPDET);

    return 0;
}


/**
 * @brief  设置DMA的数据传输长度，并启动DMA传输
 * @param  DMAy_Channelx：   相应DMA的通道
           Length：          传输长度
 * @retval 无
 */
static void vDMASetAddrAndLenthStart(uint32_t dma_periph, dma_channel_enum channelx, dma_subperipheral_enum sub_periph, int8_t cDirection, uint32_t uiMemoryAddress, uint32_t uiPeriphAddress, uint32_t uiLength)
{
    uint32_t uiTime = 0;

    uiTime = 1000000;
    /* Disable the peripheral */
    dma_channel_disable(dma_periph, channelx);
    while(((DMA_CHCTL(dma_periph, channelx) & DMA_CHXCTL_CHEN) != 0) && (--uiTime));

    /* 必须要清除所有中断状态，才允许使能DMA */
    dma_interrupt_flag_clear(dma_periph, channelx, DMA_INT_SDE | DMA_INT_TAE | DMA_INT_HTF | DMA_INT_FTF | DMA_INT_FEE);

    /* configure memory base address */
    dma_memory_address_config(dma_periph, channelx, 0, uiMemoryAddress);

    /* configure peripheral base address */
    dma_periph_address_config(dma_periph, channelx, uiPeriphAddress);

    /* Configure DMA Stream data length */
    dma_transfer_number_config(dma_periph, channelx, uiLength);

    /* configure the direction of data transfer on the channel   */
    dma_transfer_direction_config(dma_periph, channelx, cDirection);

    /* DMA channel peripheral select */
    dma_channel_subperipheral_select(dma_periph, channelx, sub_periph);

    uiTime = 1000000;
    /* Enable the Peripheral */
    dma_channel_enable(dma_periph, channelx);
    while(((DMA_CHCTL(dma_periph, channelx) & DMA_CHXCTL_CHEN) == 0) && (--uiTime));
}


/*!
    \brief      write more than one byte to the EEPROM with a single write cycle
    \param[in]  p_buffer: pointer to the buffer containing the data to be written to the EEPROM
    \param[in]  write_address: EEPROM's internal address to write to
    \param[in]  number_of_byte: number of bytes to write to the EEPROM
    \param[out] none
    \retval     none
*/
int8_t cI2CxDMAWriteDatas(uint32_t i2c_periph, uint16_t usIDAddr, uint16_t usRegAddr, uint8_t* pBuffer, int32_t iLength)
{
    void (*vI2CxBusReset)(void) = NULL;
    dma_subperipheral_enum sub_periph;
    int32_t timeout = 0, startCnt = 0;

    if(iLength <= 0)
        return -1;

    vI2CxBusReset = (i2c_periph == I2C0) ? vIIC0DeInit : vIIC1DeInit;

    /* i2c master sends start signal only when the bus is idle */
    for(timeout = 0; i2c_flag_get(i2c_periph, I2C_FLAG_I2CBSY) != RESET; ++timeout)
    {
        if(timeout > I2C_BUSY_TIME_OUT)
        {
            vI2CxBusReset();
            printf("cI2C %08X busy.\r\n", i2c_periph);
            return -2;
        }
    }

    /* 重试 N 次 */
    for(startCnt = 0; startCnt < I2C_START_OUT; ++startCnt)
    {
        if(startCnt >= I2C_START_OUT)
        {
            vI2CxBusReset();
            printf("cI2C %08X start out.\r\n", i2c_periph);
            return -3;
        }

        /* configure slave address */
        i2c_master_addressing(i2c_periph, usIDAddr, I2C_MASTER_TRANSMIT);
        /* configure number of bytes to be transferred */
        i2c_transfer_byte_number_config(i2c_periph, iLength + 1);
        /* disable I2C automatic end mode in master mode */
        i2c_automatic_end_enable(i2c_periph);

        /* clear I2C_TDATA register */
        I2C_STAT(i2c_periph) |= I2C_STAT_TBE;

        i2c_start_on_bus(i2c_periph);
        /* wait until the transmit data buffer is empty */
        for(timeout = 0; timeout < I2C_BYTE_TIME_OUT; ++timeout)
        {
            if(i2c_flag_get(i2c_periph, I2C_FLAG_TBE) != RESET)
            {
                break;
            }
        }

        /* send address */
        i2c_data_transmit(i2c_periph, usRegAddr);
        /* wait until the transmit data buffer is empty */
        for(timeout = 0; timeout < I2C_BYTE_TIME_OUT; ++timeout)
        {
            if(i2c_flag_get(i2c_periph, I2C_FLAG_TI) != RESET)
            {
                break;
            }
        }

        if(timeout < I2C_BYTE_TIME_OUT)
            break;
    }

    sub_periph = (i2c_periph == I2C0) ? DMA_SUBPERI1 : DMA_SUBPERI7;
    vDMASetAddrAndLenthStart(DMA0, DMA_CH7, sub_periph, DMA_MEMORY_TO_PERIPH, (uint32_t)pBuffer, (uint32_t)&I2C_TDATA(i2c_periph), iLength);

    // /* 等待DMA传输完成 */
    // while((dma_flag_get(DMA0, DMA_CH7, DMA_FLAG_FTF) == RESET) && ((DMA_CHCTL(DMA0, DMA_CH7) & DMA_CHXCTL_CHEN) != 0));
    // dma_flag_clear(DMA0, DMA_CH7, DMA_FLAG_FTF);

    /* wait until the stop condition is finished */
    for(timeout = 0; i2c_flag_get(i2c_periph, I2C_FLAG_STPDET) == RESET; ++timeout)
    {
        if(timeout > (I2C_BYTE_TIME_OUT * iLength))
        {
            vI2CxBusReset();
            printf("cI2C %08X stpdet.\r\n", i2c_periph);
            return -5;
        }
    }

    /* clear STPDET flag */
    i2c_flag_clear(i2c_periph, I2C_FLAG_STPDET);

    return 0;
}

/*!
    \brief      read data from the EEPROM
    \param[in]  p_buffer: pointer to the buffer that receives the data read from the EEPROM
    \param[in]  read_address: EEPROM's internal address to start reading from
    \param[in]  number_of_byte: number of bytes to reads from the EEPROM
    \param[out] none
    \retval     none
*/
int8_t cI2CxDMAReadDatas(uint32_t i2c_periph, uint16_t usIDAddr, uint16_t usRegAddr, uint8_t* pBuffer, int32_t iLength)
{
    void (*vI2CxBusReset)(void) = NULL;
    dma_channel_enum channelx;
    dma_subperipheral_enum sub_periph;
    int32_t timeout = 0, startCnt = 0;

    if(iLength <= 0)
        return -1;

    vI2CxBusReset = (i2c_periph == I2C0) ? vIIC0DeInit : vIIC1DeInit;

    /* i2c master sends start signal only when the bus is idle */
    for(timeout = 0; i2c_flag_get(i2c_periph, I2C_FLAG_I2CBSY) != RESET; ++timeout)
    {
        if(timeout > I2C_BUSY_TIME_OUT)
        {
            vI2CxBusReset();
            printf("cI2C %08X busy.\r\n", i2c_periph);
            return -2;
        }
    }

    /* 重试 N 次 */
    for(startCnt = 0; startCnt < I2C_START_OUT; ++startCnt)
    {
        if(startCnt >= I2C_START_OUT)
        {
            vI2CxBusReset();
            printf("cI2C %08X start timeout.\r\n", i2c_periph);
            return -3;
        }

        /* clear I2C_TDATA register */
        I2C_STAT(i2c_periph) |= I2C_STAT_TBE;

        /* configure slave address */
        i2c_master_addressing(i2c_periph, usIDAddr, I2C_MASTER_TRANSMIT);
        /* configure number of bytes to be transferred */
        i2c_transfer_byte_number_config(i2c_periph, 1);
        /* disable I2C automatic end mode in master mode */
        i2c_automatic_end_disable(i2c_periph);

        i2c_start_on_bus(i2c_periph);
        /* wait until the transmit data buffer is empty */
        for(timeout = 0; timeout < I2C_BUSY_TIME_OUT; ++timeout)
        {
            if(i2c_flag_get(i2c_periph, I2C_FLAG_TBE) != RESET)
            {
                break;
            }
        }

        /* send address */
        i2c_data_transmit(i2c_periph, usRegAddr);
        /* wait until the transmit data buffer is empty */
        for(timeout = 0; timeout < I2C_BYTE_TIME_OUT; ++timeout)
        {
            if(i2c_flag_get(i2c_periph, I2C_FLAG_TC) != RESET)
            {
                break;
            }
        }

        if(timeout < I2C_BYTE_TIME_OUT)
            break;
    }

    /* configure one byte address */
    i2c_master_addressing(i2c_periph, usIDAddr, I2C_MASTER_RECEIVE);
    /* configure number of bytes to be transferred */
    i2c_transfer_byte_number_config(i2c_periph, iLength);
    /* enable I2C automatic end mode in master mode */
    i2c_automatic_end_enable(i2c_periph);

    channelx = (i2c_periph == I2C0) ? DMA_CH0 : DMA_CH2;
    sub_periph = (i2c_periph == I2C0) ? DMA_SUBPERI1 : DMA_SUBPERI7;
    vDMASetAddrAndLenthStart(DMA0, channelx, sub_periph, DMA_PERIPH_TO_MEMORY, (uint32_t)pBuffer, (uint32_t)&I2C_RDATA(i2c_periph), iLength);

    /* restart */
    i2c_start_on_bus(i2c_periph);

    // /* 等待DMA传输完成 */
    // while((dma_flag_get(DMA0, channelx, DMA_FLAG_FTF) == RESET) && ((DMA_CHCTL(DMA0, channelx) & DMA_CHXCTL_CHEN) != 0));
    // dma_flag_clear(DMA0, channelx, DMA_FLAG_FTF);

    /* wait until the stop condition is finished */
    for(timeout = 0; i2c_flag_get(i2c_periph, I2C_FLAG_STPDET) == RESET; ++timeout)
    {
        if(timeout > (I2C_BYTE_TIME_OUT * iLength))
        {
            vI2CxBusReset();
            printf("cI2C %08X stpdet.\r\n", i2c_periph);
            return -5;
        }
    }

    /* clear STPDET flag */
    i2c_flag_clear(i2c_periph, I2C_FLAG_STPDET);

    return 0;
}
